#include "tlr.h"
#include <QHostAddress>
#include <QNetworkDatagram>
#include <QFile>
#include <QTimer>

/*
 * 构造函数
 * parent : 父类初始化参数
 */
TLR::TLR(QObject *parent) : QObject (parent)
{
    //其余工作
    {
        m_myIP = getTMyIPAsnIP(getAllAddressIPv4().value(0));
    }
    //信号槽
    {
        //UDP2305收到数据
        connect(m_udpSockAny,&QUdpSocket::readyRead,this,&TLR::slotUdpSockAnyReadyRead);
    }
}

Q_GLOBAL_STATIC(TLR,nlr)
/*
 * 获取单例
 * 返回值 : 单例
 */
TLR *TLR::get()
{
    return nlr();
}

/*
 * 获取指定IP的网络接口信息
 * npcip : 指定的IP
 * 返回值 : 网络接口信息
 */
QNetworkInterface TLR::getNetInfoAsnIP(QHostAddress npcip)
{
    QNetworkInterface nnetworkinterface;
    auto nlistnetinfo = QNetworkInterface::allInterfaces();
    for(auto &nnetinfo:nlistnetinfo){
        auto nlistaddress = nnetinfo.addressEntries();
        for(auto &naddress:nlistaddress){
            if(naddress.ip() == npcip){
                nnetworkinterface = nnetinfo;
            }
        }
    }
    return nnetworkinterface;
}

/*
 * 查询指定IP对应的MYIP信息
 * npcip : 指定的IP
 * 返回值 : 网络接口信息
 */
TMyIP TLR::getTMyIPAsnIP(QHostAddress npcip)
{
    TMyIP nmyip;
    auto nlistnetinfo = QNetworkInterface::allInterfaces();
    for(auto &nnetinfo:nlistnetinfo){
        auto nlistaddress = nnetinfo.addressEntries();
        for(auto &naddress:nlistaddress){
            if(naddress.ip() == npcip){
                //本机IP
                addressToIP4(npcip,nmyip.ip);
                //子网掩码
                addressToIP4(naddress.netmask(),nmyip.netmask);
                //MAC地址
                stringToMac6(nnetinfo.hardwareAddress(),nmyip.mac);
                //网关
#ifdef Q_OS_ANDROID
                //nmyip.GateWay = QHostAddress(TAndroidSupport::getGateWay());
#endif
            }
        }
    }
    return nmyip;
}

/*
 * 获取本机所有IPV4 IP信息(不会返回环回地址)
 * 返回值 : IP地址
 */
QList<QHostAddress> TLR::getAllAddressIPv4()
{
    QList<QHostAddress> nlistaddress;
    auto nalladdress = QNetworkInterface::allAddresses();
    for(auto &naddress:nalladdress){
        if(!naddress.isLoopback()){
            if(naddress.protocol() == QAbstractSocket::IPv4Protocol){
                nlistaddress.append(naddress);
            }
        }
    }
    return nlistaddress;
}

/**********
 * 辅助_4字节IP转地址
 * nip    :  待转换IP
 * 返回值  :  IP地址
**********/
QHostAddress TLR::ip4toAddress(const u8 nip[])
{
    u8 niptmp[4];
    niptmp[0] = nip[3];
    niptmp[1] = nip[2];
    niptmp[2] = nip[1];
    niptmp[3] = nip[0];
    QHostAddress nipaddr;
    quint32 nipint;
    memcpy(&nipint,niptmp,4);
    nipaddr.setAddress(nipint);
    return nipaddr;
}

/*
 * 辅助_IP地址转4字节
 * nipstr  :  IP地址
 * nip     :  4字节IP
 */
void TLR::addressToIP4(QHostAddress nipaddr,u8 nip[4])
{
    //由于计算机是按照小端存储基本数据类型的所以这里转换的IP地址
    //需要反一下才行
    quint32 nipint32 = nipaddr.toIPv4Address();
    u8 niptmp[4];
    memcpy(niptmp,&nipint32,4);
    nip[0] = niptmp[3];
    nip[1] = niptmp[2];
    nip[2] = niptmp[1];
    nip[3] = niptmp[0];
}

/*
 * 辅助_MAC字符串转6字节
 * nmacstr  :  IP地址
 * nmac     :  4字节IP
 * nsplit   :  分割符(可缺省)
 */
void TLR::stringToMac6(const QString &nmacstr, u8 nmac[],const QString &nsplit)
{
    memset(nmac,0x00,6);
    QStringList nmaclist = nmacstr.split(nsplit);
    if(nmaclist.size() == 6){
        for(int ii=0;ii<6;ii++){
            nmac[ii] = static_cast<u8>(nmaclist.at(ii).toInt(nullptr,16));
        }
    }
}

/*
 * 辅助_MAC地址6字节转字符串
 * nmac   : mac地址6字节
 * nsplit : 分割符(可缺省)
 */
QString TLR::mac6ToString(const u8 nmac[], const QString &nsplit)
{
    QString nmacstr;
    nmacstr = QString("%1"+nsplit+"%2"+nsplit+"%3"+nsplit+"%4"+nsplit+"%5"+nsplit+"%6")
            .arg(nmac[0],2,16,QChar('0'))
            .arg(nmac[1],2,16,QChar('0'))
            .arg(nmac[2],2,16,QChar('0'))
            .arg(nmac[3],2,16,QChar('0'))
            .arg(nmac[4],2,16,QChar('0'))
            .arg(nmac[5],2,16,QChar('0'));
    nmacstr = nmacstr.toUpper();
    return nmacstr;
}

/*
 * 辅助_获取指定IP的MAC地址(仅WIN平台)
 * nip   : 指定IP
 * 返回值 : MAC地址
 */
void TLR::getMacAsnIP(const QHostAddress &nip, u8 nmac[])
{
#ifdef Q_OS_WIN
    //IP要转换位IPV4地址
//    QHostAddress nipv4 = QHostAddress(nip.toIPv4Address());
//    IPAddr ndestip = 0;
//    ULONG nphysAddrLen = 6;  /* default to length of six bytes */
//    ndestip = inet_addr(nipv4.toString().toUtf8().data());
//    if(!nipv4.isBroadcast()) {
//        SendARP(ndestip,INADDR_ANY,nmac,&nphysAddrLen);
//    }
//    //过滤非法数据(全0xff)
//    if(nmac[0] == 0xff && nmac[0] == 0xff && nmac[0] == 0xff &&
//            nmac[0] == 0xff && nmac[0] == 0xff && nmac[0] == 0xff) {
//        memset(nmac,0x00,6);
//    }
#endif
}

/*
 * 计算offsetof(因为传统的offsetof不能加入变量表达式)
 * nsta  : 起始位置
 * ndest : 比较位置
 * 返回值 : 偏移量
 */
int TLR::dynOffsetof(const void *nsta, const void *ndest)
{
    int noffset = 0;
    noffset = static_cast<const char*>(ndest) -
            static_cast<const char*>(nsta);
    return noffset;
}

#ifdef SSD202
/*
 * 4字节IP转换为U32
 * ip      :  IP地址
 * return :  U32的IP地址
*/
in_addr_t TLR::ip4ToAddr(const u8 ip[])
{
    in_addr_t u32ip = 0;
    u32ip = ip[0] + (ip[1] << 8 )+ (ip[2] << 16) + (ip[3] << 24);
    return u32ip;
}

/*
 * 开关指定网卡
 * interface_name : 网卡名称
 * onoff          : HI_FALSE:关 HI_TRUE:开
 * 返回值          : 0:成功 -1:失败
 */
int TLR::ctlEthernet(const char *interface_name, bool onoff)
{
    int 	     sock_fd;
    struct ifreq ifr;
    int			 selector;

    /* 传入参数合法性检测 */
    if(interface_name == NULL) {
        return -1;
    }
    /* 禁止关闭回环 */
    if(strncmp(interface_name, "lo", 2) == 0) {
        return -1;
    }
    /* 创建一个SOCKET */
    sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sock_fd < 0) {
        return -1;
    }
    //将网络接口名称填入
    strncpy(ifr.ifr_name, interface_name,15);
    if(ioctl(sock_fd, SIOCGIFFLAGS, &ifr) < 0) {
        return -1;
    }
    //开
    if(onoff) {
        selector = IFF_UP | IFF_RUNNING;
        ifr.ifr_flags |= selector;
        if(ioctl(sock_fd, SIOCSIFFLAGS, &ifr) < 0) {
            return -1;
        }
    }
    //关
    else {
        selector = IFF_UP;
        ifr.ifr_flags &= ~selector;
        if(ioctl(sock_fd, SIOCSIFFLAGS, &ifr) < 0) {
            return -1;
        }
    }

    close(sock_fd);
    return 0;
}

/*
 * 修改IP
 * interface_name : 网卡名称(如eth0)
 * ip             : ip地址(4个字节)
 * 返回值          : 0:成功 -1:失败
 */
int TLR::setSysip(const char *interface_name, const u8 ip[])
{
    int sockfd;
    int ret = 0;
    struct ifreq ifr;
    struct sockaddr_in ip_addr;

    /* 填写接口名称 */
    strncpy(ifr.ifr_name, interface_name,15);

    /* 填写IP */
    ip_addr.sin_family = AF_INET;
    ip_addr.sin_addr.s_addr = ip4ToAddr(ip);

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0) {
        return -1;
    }

    /* 设置IP */
    memcpy(&(ifr.ifr_addr), &ip_addr, sizeof (struct sockaddr));
    ret = ioctl(sockfd, SIOCSIFADDR, &ifr);
    if(ret < 0) {
        return -1;
    }

    /* 启动网卡 */
    ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
    ret = ioctl(sockfd, SIOCSIFFLAGS, &ifr);
    if(ret < 0) {
        return -1;
    }
    return 0;
}

/*
 * 修改MASK
 * interface_name : 网卡名称(如eth0)
 * netmask        : 子网掩码(4个字节)
 * 返回值          : 0:成功 -1:失败
 */
int TLR::setSysMask(const char *interface_name, const u8 netmask[])
{
     int sockfd;
     int ret = 0;
     struct ifreq ifr;
     struct sockaddr_in netmask_addr;

     /* 填写接口名称 */
     strncpy(ifr.ifr_name, interface_name,15);

     /* 填写子网掩码 */
     netmask_addr.sin_family = AF_INET;
     memcpy(&netmask_addr.sin_addr.s_addr,netmask,4);
     netmask_addr.sin_addr.s_addr = ip4ToAddr(netmask);

     sockfd = socket(AF_INET, SOCK_DGRAM, 0);
     if(sockfd < 0) {
         return -1;
     }

     /* 设置子网掩码 */
     memcpy(&(ifr.ifr_addr), &netmask_addr, sizeof (struct sockaddr));
     ret = ioctl(sockfd, SIOCSIFNETMASK, &ifr);
     if(ret < 0) {
         return -1;
     }

     /* 启动网卡 */
     ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
     ret = ioctl(sockfd, SIOCSIFFLAGS, &ifr);
     if(ret < 0) {
         return -1;
     }
     return 0;
}

/*
 * 增减网关
 * gateway  : 网关IP(4个字节)
 * addordel : true:增加 false:删除
 * 返回值    : 0:成功 -1:失败
 */
int TLR::setSysGateWay(const u8 gateway[], bool addordel)
{
    int ret = -1;
    int fd = socket( AF_INET, SOCK_DGRAM, IPPROTO_IP );

    struct rtentry route;
    memset(&route,0,sizeof(route));

    /* sockaddr_in sockaddr 两个结构体是可以互相转换的 直接指针互相指 */
    struct sockaddr_in *addr = (struct sockaddr_in *)&route.rt_gateway;
    addr->sin_family = AF_INET;
    addr->sin_addr.s_addr = ip4ToAddr(gateway);

    addr = (struct sockaddr_in*) &route.rt_dst;
    addr->sin_family = AF_INET;
    addr->sin_addr.s_addr = INADDR_ANY;

    addr = (struct sockaddr_in*) &route.rt_genmask;
    addr->sin_family = AF_INET;
    addr->sin_addr.s_addr = INADDR_ANY;

    route.rt_flags = RTF_UP | RTF_GATEWAY;
    route.rt_metric = 0;

    /* 增加 */
    if(addordel) {
        ret = ioctl(fd, SIOCADDRT, &route);
    }
    /* 删除 */
    else {
        ret = ioctl(fd, SIOCDELRT, &route);
    }
    if(ret < 0) {
        return -1;
    }
    return 0;
}

/*
 * 修改mac地址
 * interface_name : 网卡名称(如eth0)
 * mac            : mac地址(6个字节)
 * 返回值          : 0:成功 -1:失败
 */
int TLR::setSysMac(const char *interface_name, const u8 mac[])
{
    struct ifreq ifr;
    int ret = -1;
    int sockfd = -1;
    /* 首先关闭网络 */
    ret = ctlEthernet(interface_name,false);
    if(ret < 0)  {
        return -1;
    }

    /* 填写mac地址 */
    memcpy(ifr.ifr_hwaddr.sa_data,mac,6);

    /* 打开socket */
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(sockfd < 0)
    {
        return -1;
    }

    /* 填写网卡名称 */
    strncpy(ifr.ifr_name, interface_name,15);
    ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
    ret = ioctl(sockfd, SIOCSIFHWADDR, &ifr);
    if(ret < 0)
    {
        return -1;
    }

    /* 重新打开网络 */
    ret = ctlEthernet(interface_name,true);
    if(ret < 0)  {
        return -1;
    }
    return 0;
}
#endif

/*
 * LR标准协议_读取数据
 * nequidstr : 设备识别字
 * startpos  : 起始位置
 * paranum   : 数据数量
 * 返回值     : 数据包
 */
QList<QByteArray> TLR::rdPara(QString nequidstr,int startpos, int paranum)
{
    QList<QByteArray> nlistbytes;
    int npkgnum = paranum / 1024;
    npkgnum += paranum % 1024?1:0;
    for(int ipkg=0;ipkg<npkgnum;ipkg++){
        TUDPSysPara nudpsyspara;
        //指令
        strcpy(nudpsyspara.Cmd,"SetPara");
        //识别字
        strncpy(nudpsyspara.IdentifyingCode,nequidstr.toStdString().data(),20);
        nudpsyspara.StartByte = 0xca;
        nudpsyspara.CmdType = 0x03;
        //起始地址
        nudpsyspara.ParaStaAdd = static_cast<u16>(startpos + ipkg*1024);
        //数据数量
        u16 nremainsize = static_cast<u16>(startpos + paranum) - nudpsyspara.ParaStaAdd;
        nudpsyspara.ParaNum = nremainsize >= 1024?1024:nremainsize;

        QByteArray nsndbyte;
        nsndbyte.resize(sizeof (TUDPSetParaConfirm));
        memcpy(nsndbyte.data(),&nudpsyspara,static_cast<size_t>(nsndbyte.size()));
        nlistbytes.append(nsndbyte);
    }
    return nlistbytes;
}

/*
 * LR标准协议_读取数据(串口)
 * nequidstr : 设备识别字
 * startpos  : 起始位置
 * paranum   : 数据数量
 * 返回值     : 数据包
 */
QList<QByteArray> TLR::rdParaSerial(QString nequidstr, int startpos, int paranum, quint16 naddr)
{
    QList<QByteArray> nlistbytes;
    int npkgnum = paranum / 1024;
    npkgnum += paranum % 1024?1:0;
    for(int ipkg=0;ipkg<npkgnum;ipkg++){
        TUDPSysPara nudpsyspara;
        //指令
        strcpy(nudpsyspara.Cmd,"SetPara");
        //地址
        nudpsyspara.Cmd[8] = char(naddr % 256);
        nudpsyspara.Cmd[9] = char(naddr / 256);
        //识别字
        strncpy(nudpsyspara.IdentifyingCode,nequidstr.toStdString().data(),20);
        nudpsyspara.StartByte = 0xca;
        nudpsyspara.CmdType = 0x03;
        //起始地址
        nudpsyspara.ParaStaAdd = static_cast<u16>(startpos + ipkg*1024);
        //数据数量
        u16 nremainsize = static_cast<u16>(startpos + paranum) - nudpsyspara.ParaStaAdd;
        nudpsyspara.ParaNum = nremainsize >= 1024?1024:nremainsize;

        QByteArray nsndbyte;
        nsndbyte.resize(sizeof (TUDPSetParaConfirm));
        memcpy(nsndbyte.data(),&nudpsyspara,static_cast<size_t>(nsndbyte.size()));
        nlistbytes.append(nsndbyte);
    }
    return nlistbytes;
}

/*
 * LR标准协议_下载数据
 * nequidstr : 设备识别字
 * startpos  : 起始位置
 * paranum   : 数据量
 * dp        : 源数据指针
 * 返回值     : 数据包
 */
QList<QByteArray> TLR::wrPara(QString nequidstr,int startpos, int paranum, const void *dp)
{
    QList<QByteArray> nlistbytes;
    int npkgnum = paranum / 1024;
    npkgnum += paranum % 1024?1:0;
    for(int ipkg=0;ipkg<npkgnum;ipkg++){
        TUDPSysPara nudpsyspara;
        //指令
        strcpy(nudpsyspara.Cmd,"SetPara");
        //识别字
        strncpy(nudpsyspara.IdentifyingCode,nequidstr.toStdString().data(),20);
        nudpsyspara.StartByte = 0xca;
        nudpsyspara.CmdType = 0x10;
        //起始地址
        nudpsyspara.ParaStaAdd = static_cast<u16>(startpos + ipkg*1024);
        //数据数量
        u16 nremainsize = static_cast<u16>(startpos + paranum) - nudpsyspara.ParaStaAdd;
        nudpsyspara.ParaNum = nremainsize >= 1024?1024:nremainsize;
        //实际数据
        memcpy(nudpsyspara.Para,reinterpret_cast<const char*>(dp)+ipkg*1024,nudpsyspara.ParaNum);

        QByteArray nsndbyte;
        nsndbyte.resize(sizeof (TUDPSetParaConfirm) + nudpsyspara.ParaNum);
        memcpy(nsndbyte.data(),&nudpsyspara,static_cast<size_t>(nsndbyte.size()));
        nlistbytes.append(nsndbyte);
    }
    return nlistbytes;
}

/*
 * LR标准协议_下载数据
 * nequidstr : 设备识别字
 * startpos  : 起始位置
 * paranum   : 数据量
 * dp        : 源数据指针
 * 返回值     : 数据包
 */
QList<QByteArray> TLR::ctlPara(QString nequidstr, int startpos, int paranum, const void *dp)
{
    QList<QByteArray> nlistbytes;
    int npkgnum = paranum / 1024;
    npkgnum += paranum % 1024?1:0;
    for(int ipkg=0;ipkg<npkgnum;ipkg++){
        TUDPSysPara nudpsyspara;
        //指令
        strcpy(nudpsyspara.Cmd,"SetPara");
        //识别字
        strncpy(nudpsyspara.IdentifyingCode,nequidstr.toStdString().data(),20);
        nudpsyspara.StartByte = 0xca;
        nudpsyspara.CmdType = 0x06;
        //起始地址
        nudpsyspara.ParaStaAdd = static_cast<u16>(startpos + ipkg*1024);
        //数据数量
        u16 nremainsize = static_cast<u16>(startpos + paranum) - nudpsyspara.ParaStaAdd;
        nudpsyspara.ParaNum = nremainsize >= 1024?1024:nremainsize;
        //实际数据
        memcpy(nudpsyspara.Para,reinterpret_cast<const char*>(dp)+ipkg*1024,nudpsyspara.ParaNum);

        QByteArray nsndbyte;
        nsndbyte.resize(sizeof (TUDPSetParaConfirm) + nudpsyspara.ParaNum);
        memcpy(nsndbyte.data(),&nudpsyspara,static_cast<size_t>(nsndbyte.size()));
        nlistbytes.append(nsndbyte);
    }
    return nlistbytes;
}

/*
 * LR标准协议_读取FLASH数据
 * address : 串口通讯时用的，是设备地址，网络时不关心
 * staadd  : 要擦除或编程的 FLASH 的绝对地址  操作45DB161时，以528为单位，操作CPU内部FLASH时，以1024为单位
 * datlen  : 就是要操作的数据  操作45db16的时候不可以超过 528
 * 返回值   : 数据包
 */
QList<QByteArray> TLR::rdParaFlash(int address, int staadd, int datlen)
{
    QList<QByteArray> nlistbytes;
    int npkgnum = datlen / 1024;
    npkgnum += datlen % 1024?1:0;
    for(int ipkg=0;ipkg<npkgnum;ipkg++){
        TFlashProg nflashprog;
        //串口地址
        nflashprog.Address = static_cast<u16>(address);
        //指令
        strcpy(nflashprog.Cmd,"FlashReadPage");
        //起始地址
        nflashprog.StaAdd = static_cast<u32>(staadd + 1024*ipkg);
        //数据长度
        u32 nremainsize = static_cast<u32>(datlen + staadd) - nflashprog.StaAdd;
        nflashprog.DatLen = nremainsize >= 1024?1024:nremainsize;
        QByteArray nsndbyte;
        nsndbyte.resize(sizeof (TFlashProg));
        memcpy(nsndbyte.data(),&nflashprog,static_cast<size_t>(nsndbyte.size()));
        nlistbytes.append(nsndbyte);
    }
    return nlistbytes;
}

/*
 * LR标准协议_下载FLASH数据
 * address : 串口通讯时用的，是设备地址，网络时不关心
 * staadd  : 要擦除或编程的 FLASH 的绝对地址  操作45DB161时，以528为单位，操作CPU内部FLASH时，以1024为单位
 * datlen  : 就是要操作的数据  操作45db16的时候不可以超过 528
 * pdata   : 原始数据
 * 返回值   : 数据包
 */
QList<QByteArray> TLR::wrParaFlash(int address, int staadd, int datlen, const void *pdata)
{
    QList<QByteArray> nlistbytes;
    int npkgnum = datlen / 1024;
    npkgnum += datlen % 1024?1:0;
    for(int ipkg=0;ipkg<npkgnum;ipkg++){
        TFlashProg nflashprog;
        //串口地址
        nflashprog.Address = static_cast<u16>(address);
        //指令
        strcpy(nflashprog.Cmd,"FlashWritePage");
        //起始地址
        nflashprog.StaAdd = static_cast<u32>(staadd + 1024*ipkg);
        //数据长度
        u32 nremainsize = static_cast<u32>(datlen + staadd) - nflashprog.StaAdd;
        nflashprog.DatLen = nremainsize >= 1024?1024:nremainsize;
        //数据
        memcpy(nflashprog.databuf,reinterpret_cast<const char*>(pdata)+1024*ipkg,nflashprog.DatLen);
        QByteArray nsndbyte;
        nsndbyte.resize(sizeof (TFlashProg));
        memcpy(nsndbyte.data(),&nflashprog,static_cast<size_t>(nsndbyte.size()));
        nlistbytes.append(nsndbyte);
    }
    return nlistbytes;
}

/*
 * LR标准协议_合成数据
 * nequidstr : 设备识别字
 * startpos  : 起始位置
 * paranum   : 数据数量
 * ncmdtype  : 指令类型
 * ncmd      : 指令
 * 返回值     : 数据包
 */
QList<QByteArray> TLR::makePara(QString nequidstr, int startpos, int paranum, int ncmdtype, const QByteArray &ncmd)
{
    QList<QByteArray> nlistbytes;
    int npkgnum = paranum / 1024;
    npkgnum += paranum % 1024?1:0;
    if(paranum == 0) {
        npkgnum = 1;
    }
    for(int ipkg=0;ipkg<npkgnum;ipkg++){
        TUDPSysPara nudpsyspara;
        //指令
        strncpy(nudpsyspara.Cmd,ncmd.constData(),9);
        //识别字
        strncpy(nudpsyspara.IdentifyingCode,nequidstr.toStdString().data(),19);
        nudpsyspara.StartByte = 0xca;
        nudpsyspara.CmdType = u8(ncmdtype);
        //起始地址
        nudpsyspara.ParaStaAdd = static_cast<u16>(startpos + ipkg*1024);
        //数据数量
        u16 nremainsize = static_cast<u16>(paranum - ipkg*1024);
        nudpsyspara.ParaNum = nremainsize >= 1024?1024:nremainsize;

        QByteArray nsndbyte;
        nsndbyte.resize(sizeof (TUDPSetParaConfirm));
        memcpy(nsndbyte.data(),&nudpsyspara,static_cast<size_t>(nsndbyte.size()));
        nlistbytes.append(nsndbyte);
    }
    return nlistbytes;
}

/*
 * LR标准协议_FLASH指令报文
 * address  : 串口通讯时用的，是设备地址，网络时不关心
 * staadd   : 要擦除或编程的 FLASH 的绝对地址  操作45DB161时，以528为单位，操作CPU内部FLASH时，以1024为单位
 * datlen   : 就是要操作的数据  操作45db16的时候不可以超过 528
 * ncmdbyte : 指令
 * 返回值    : 数据包
 */
QByteArray TLR::packFlashAddCmd(int address, int staadd, int datlen, QByteArray ncmdbyte)
{
    QByteArray nsigbyte;
    TFlashAddCmd nflashaddcmp{};
    //地址
    nflashaddcmp.Address = static_cast<u16>(address);
    //指令
    strncpy(nflashaddcmp.Cmd,ncmdbyte.data(),sizeof (nflashaddcmp.Cmd));
    //起始地址
    nflashaddcmp.StaAdd = static_cast<u32>(staadd);
    //数据长度
    nflashaddcmp.DatLen = static_cast<u32>(datlen);
    nsigbyte.resize(sizeof (nflashaddcmp));
    memcpy(nsigbyte.data(),&nflashaddcmp,static_cast<size_t>(nsigbyte.size()));
    return nsigbyte;
}

/*
 * LR标准协议_搜索在线设备
 * 返回值  :  数据包
*/
QByteArray TLR::searchEqu()
{
    QByteArray nqbyte;
    TUDPAddressPara nudpaddresspara;
    strcpy(nudpaddresspara.Cmd,"GetNetPara");
    nqbyte.resize(sizeof (nudpaddresspara));
    memcpy(nqbyte.data(),&nudpaddresspara,static_cast<size_t>(nqbyte.size()));
    return nqbyte;
}

/*
 * 广播设置IP
 * uid  : 设备UID
 * nmac : MAC地址
 * nip  : IP地址
 */
QByteArray TLR::bcastSetIP(char uid[],u8 nmac[], u8 nip[])
{
    TUDPSysPara nudpsyspara;
    //指令
    strcpy(nudpsyspara.Cmd,"BrdSetP");
    //识别字(UID + MAC)
    memcpy(nudpsyspara.IdentifyingCode,uid,14);
    memcpy(nudpsyspara.IdentifyingCode+14,nmac,6);
    nudpsyspara.StartByte = 0xca;
    nudpsyspara.CmdType = 0x06;
    //起始地址
    nudpsyspara.ParaStaAdd = offsetof(TAddressPara,ip);
    //数据数量
    nudpsyspara.ParaNum = 4;
    //实际数据
    memcpy(nudpsyspara.Para,nip,nudpsyspara.ParaNum);

    QByteArray nsndbyte;
    nsndbyte.resize(sizeof (TUDPSetParaConfirm) + nudpsyspara.ParaNum);
    memcpy(nsndbyte.data(),&nudpsyspara,static_cast<size_t>(nsndbyte.size()));
    return nsndbyte;
}

/*
 * LR标准协议_校时
 * 返回值 : 数据包
 */
QByteArray TLR::calibTime()
{
    TUDPCalibTime nudpcalibtime;
    QDateTime ndatetime = QDateTime::currentDateTime();

    strcpy(nudpcalibtime.Cmd,"CalibDateTime");
    nudpcalibtime.DT.year = static_cast<u8>(ndatetime.date().year()-2000);
    nudpcalibtime.DT.month = static_cast<u8>(ndatetime.date().month());
    nudpcalibtime.DT.date = static_cast<u8>(ndatetime.date().day());
    nudpcalibtime.DT.hour = static_cast<u8>(ndatetime.time().hour());
    nudpcalibtime.DT.min = static_cast<u8>(ndatetime.time().minute());
    nudpcalibtime.DT.sec = static_cast<u8>(ndatetime.time().second());
    nudpcalibtime.DT.msCnt = static_cast<u8>(ndatetime.time().msec());
    nudpcalibtime.DT.weekday = static_cast<u8>(ndatetime.date().dayOfWeek());
    QByteArray nsndbyte;
    nsndbyte.resize(sizeof(TUDPCalibTime));
    memcpy(nsndbyte.data(),&nudpcalibtime,sizeof (TUDPCalibTime));
    return nsndbyte;
}

/*
 * LR标准协议_IAP指令
 * ncmd    : 指令
 * 返回值   : IAP指令字节
 */
QByteArray TLR::packIapSigCmd(const QByteArray &ncmd)
{
    QByteArray niapbyte;
    TIAPSigCmd niapsigcmd;
    strncpy(niapsigcmd.Cmd,ncmd.constData(),15);
    niapbyte.resize(sizeof (niapsigcmd));
    memcpy(niapbyte.data(),&niapsigcmd,sizeof(niapsigcmd));
    return niapbyte;
}

/*
 * 延时
 * nmsec : 毫秒
 */
void TLR::delayMs(int nmsec)
{
    if(nmsec > 0) {
        QEventLoop nloop;
        QTimer::singleShot(nmsec,&nloop,&QEventLoop::quit);
        nloop.exec();
    }
}

/*
 * UDP发送数据
 * nsndbyte : 发送的数据
 * nip      : 目标IP
 * nport    : 目标端口
 */
void TLR::udpSockAnyWrite(const QByteArray &nsndbyte, const QHostAddress &nip, int nport)
{
    m_udpSockAny->writeDatagram(nsndbyte,nip,static_cast<u16>(nport));
}

/*
 * UDP发送数据
 * nsndbytes : 发送的数据
 * nip       : 目标IP
 * nport     : 目标端口
 */
void TLR::udpSockAnyWrite(const QList<QByteArray> &nsndbytes, const QHostAddress &nip, int nport)
{
    for(const QByteArray &nsndbyte:nsndbytes) {
        m_udpSockAny->writeDatagram(nsndbyte,nip,static_cast<u16>(nport));
    }
}

/*
 * 设置IP
 * nip : IP
 */
void TLR::setMyIP(const QHostAddress &nip)
{
    m_myIP = getTMyIPAsnIP(nip);
    //重新bind
    m_udpSockAny->disconnectFromHost();
    m_udpSockAny->bind(nip);
}

/*
 * 获取本机IP
 */
TMyIP TLR::getMyIP()
{
    return m_myIP;
}

/*
 * 打开串口
 * nportname : 串口名称
 * nbaud     : 波特率
 * 返回值     : true 打开成功 false 打开失败
 */
bool TLR::openSerialPort(const QString &nportname, qint32 nbaud)
{
    bool nret = false;
    m_commUart.setPort(QSerialPortInfo(nportname));
    m_commUart.open(QSerialPort::ReadWrite);
    m_commUart.setBaudRate(nbaud);
    m_commUart.setDataBits(QSerialPort::Data8);
    m_commUart.setParity(QSerialPort::NoParity);
    m_commUart.setReadBufferSize(1024);
    nret = m_commUart.isOpen();
    return nret;
}

/*
 * 关闭串口
 */
void TLR::closeSerialPort()
{
    if(m_commUart.isOpen()) {
        m_commUart.close();
    }
}

/*
 * 获取当前使用的串口名称
 * 返回值 : 当前使用的串口名称
 */
QString TLR::getCurrentPortName()
{
    QString nportname;
    if(m_commUart.isOpen()) {
        nportname = m_commUart.portName();
    }
    return nportname;
}

/*
 * 串口发送数据
 * nsndbyte  : 待发送数据
 * nreadsize : 待接收数据长度
 */
void TLR::serialPortWrite(const QByteArray &nsndbyte,int nreadsize)
{
    if(m_commUart.isOpen() && !m_serialPortLock) {
        m_serialPortLock = true;
        m_commUart.clear();
        m_commUart.write(nsndbyte);
        //等待发送完成以及接收完成
        delayMs(int((nsndbyte.size()*10.5/m_commUart.baudRate()*1000 + nreadsize*10.5/m_commUart.baudRate()*1000 + 20)*2));
        QByteArray nreadbyte = m_commUart.readAll();
        dataToStruct(nreadbyte);
        m_serialPortLock = false;
    }
}

/*
 * 串口发送数据
 * nsndbytes  : 待发送数据
 * nreadsizes : 待接收数据长度
 */
void TLR::serialPortWrite(const QList<QByteArray> &nsndbytes, const QList<int> nreadsizes)
{
    if(nsndbytes.size() == nreadsizes.size()) {
        if(m_commUart.isOpen() && !m_serialPortLock) {
            m_serialPortLock = true;
            int nindex = 0;
            for(const QByteArray &nsndbyte:nsndbytes) {
                int nreadsize = nreadsizes.at(nindex);
                m_commUart.clear();
                m_commUart.write(nsndbyte);
                //等待发送完成以及接收完成
                delayMs(int((nsndbyte.size()*10.5/m_commUart.baudRate()*1000 + nreadsize*10.5/m_commUart.baudRate()*1000 + 20)*2));
                QByteArray nreadbyte = m_commUart.readAll();
                dataToStruct(nreadbyte);
                nindex += 1;
            }
            m_serialPortLock = false;
        }
    }
}

/*
 * 数据分配给结构体
 * nreadbyte : 数据
 */
void TLR::dataToStruct(const QByteArray &nreadbyte)
{
    if(!nreadbyte.isEmpty()){
        const TUDPSysPara *pudpsyspara = reinterpret_cast<const TUDPSysPara*>(nreadbyte.data());
        if(m_lrStructModel.isIndexValid(m_lrStructModel.getCommIndex())) {
            TLRStruct &nlrstruct = m_lrStructModel.m_lrstructModel[m_lrStructModel.getCommIndex()];
            if(nlrstruct.isMatch(pudpsyspara->ParaStaAdd,pudpsyspara->ParaNum)) {
                //读取
                if(pudpsyspara->CmdType == 0x03) {
                    nlrstruct.memParaCopy(pudpsyspara->Para,pudpsyspara->ParaNum);
                    emit sigStructDataUpdate();
                    emit sigToolTip("读取成功");
                }
                //下发
                else {
                    emit sigToolTip("下发成功");
                }
            }
        }
    }
}

/*
 * 收到UDP数据
 */
void TLR::slotUdpSockAnyReadyRead()
{
    while (m_udpSockAny->hasPendingDatagrams()) {
        QNetworkDatagram ndatagram = m_udpSockAny->receiveDatagram();
        QByteArray nreadbyte = ndatagram.data();
        QHostAddress npeerip = ndatagram.senderAddress();
        dataToStruct(nreadbyte);
    }
}
